package connect5.ia;

/*
 * Si vous utilisez Java, vous devez modifier ce fichier-ci.
 *
 * Vous pouvez ajouter d'autres classes sous le package connect5.ia.
 * 
 *
 * Prénom Nom    (00 000 000)
 * Prénom Nom    (00 000 000)
 */

import java.util.Vector;

import javax.swing.plaf.basic.BasicInternalFrameTitlePane.MaximizeAction;

import connect5.Grille;
import connect5.Joueur;

/**
 * 
 * @author Vos noms et matricules
 */
public class JoueurArtificiel implements Joueur {

	private static final int MIN_LEVEL = 0;

	private static final int BLACK_MOVE = 1;

	private static final int WHITE_MOVE = 2;

	private static final int BLANK_SPACE = 0;

	private GridAnalyser analyser = new GridAnalyser();

	@Override
	public int[] getProchainCoup(Grille g, int delais) {

		Grille gridCopy = g.clone();

		int nbcol = g.getData()[0].length;
		Integer position_to_play = new Integer(-1);
		int levelDepth = 2;

		Vector<Integer> vides = extractEmptySpaces(gridCopy, nbcol);

		if (isBlackPlaying(g.getSize(), vides.size())) {
			position_to_play = nextMaxMove(gridCopy, nbcol, levelDepth);
		} else {

			position_to_play = nextMinMove(gridCopy, nbcol, levelDepth);
		}

		return new int[] { position_to_play / nbcol, position_to_play % nbcol };
	}

	private Integer nextMaxMove(Grille gridCopy, int nbcol, int levelDepth) {
		long actual_value;
		Integer positionToPlay = new Integer(-1);
		long alpha = -2130000000;
		long beta = 2130000000;

		Vector<Integer> vides = extractEmptySpaces(gridCopy, nbcol);

		for (Integer one_integer : vides) {

			gridCopy.set(one_integer / nbcol, one_integer % nbcol, BLACK_MOVE);

			actual_value = minValue(gridCopy, nbcol, levelDepth -1, alpha, beta);

			if (actual_value > alpha) {
				alpha = actual_value;
				positionToPlay = one_integer;
			}

			resetPositionToEmpty(gridCopy, nbcol, one_integer);
		}

		return positionToPlay;
	}

	private long maxValue(Grille gridCopy, int nbcol, int levelDepth, long alpha, long beta) {

		if (levelDepth > MIN_LEVEL) {

			Vector<Integer> vides = extractEmptySpaces(gridCopy, nbcol);
			long actualValue;

			for (Integer onePosition : vides) {
				gridCopy.set(onePosition / nbcol, onePosition % nbcol,
						BLACK_MOVE);
				actualValue = minValue(gridCopy, nbcol, levelDepth -1, alpha, beta);
				
				if (actualValue > alpha) {
					alpha = actualValue;
				}

				resetPositionToEmpty(gridCopy, nbcol, onePosition);
				
				if(actualValue == -2000000000){
					return actualValue;
				}
				
				if(beta <= alpha){
					return alpha;
				}
			}
			return alpha;
		}

		return evaluateBlackPositionValue(gridCopy);
	}

	private Integer nextMinMove(Grille gridCopy, int nbcol, int levelDepth) {
		long actual_value;
		long alpha = -2130000000;
		long beta = 2130000000;

		Vector<Integer> vides = extractEmptySpaces(gridCopy, nbcol);
		Integer position_to_play = new Integer(-1);

		for (Integer one_integer : vides) {

			gridCopy.set(one_integer / nbcol, one_integer % nbcol, WHITE_MOVE);
			actual_value = maxValue(gridCopy, nbcol, levelDepth -1, alpha, beta);

			if (actual_value < beta) {
				beta = actual_value;
				position_to_play = one_integer;
			}

			resetPositionToEmpty(gridCopy, nbcol, one_integer);
		}

		return position_to_play;
	}

	private long minValue(Grille gridCopy, int nbcol, int levelDepth, long alpha, long beta) {

		if (levelDepth > MIN_LEVEL) {

			long actualValue;

			Vector<Integer> vides = extractEmptySpaces(gridCopy, nbcol);

			for (Integer onePosition : vides) {
				gridCopy.set(onePosition / nbcol, onePosition % nbcol,
						WHITE_MOVE);

				actualValue = maxValue(gridCopy, nbcol, levelDepth -1, alpha, beta);
				
				if (actualValue < beta) {
					beta = actualValue;
				}
				resetPositionToEmpty(gridCopy, nbcol, onePosition);
				
				if(actualValue == 2000000000){
					return actualValue;
				}
				
				if(beta <= alpha){
					return beta;
				}
				
			}

			return beta;
		}

		return evaluateWhitePositionValue(gridCopy);
	}

	private Vector<Integer> extractEmptySpaces(Grille g, int nbcol) {

		Vector<Integer> vides = new Vector<Integer>();

		for (int l = 0; l < g.getData().length; l++)
			for (int c = 0; c < nbcol; c++)
				if (g.getData()[l][c] == 0)
					vides.add(l * nbcol + c);

		return vides;
	}

	private void resetPositionToEmpty(Grille gridCopy, int nbcol,
			Integer one_integer) {
		gridCopy.set(one_integer / nbcol, one_integer % nbcol, BLANK_SPACE);
	}

	private long evaluateWhitePositionValue(Grille gridCopy) {
		return analyser.analyseGrid(gridCopy);
	}

	private long evaluateBlackPositionValue(Grille gridCopy) {
		return analyser.analyseGrid(gridCopy);
	}

	private boolean isBlackPlaying(int grid_size, int vide_size) {
		return ((grid_size - vide_size) % 2 == 0);
	}

	private void Utility() {

	}

}
